////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews
{
    using System;

    using Mews.UnitTesting;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>Tests the <see cref="ScopeGuard"/> class.</summary>
    [TestClass]
    public sealed class ScopeGuardTest : TestBase
    {
        /// <summary>Tests the normal course of events.</summary>
        [TestMethod]
        public void NormalTest()
        {
            Disposable disposable = new Disposable();
            ScopeGuard<Disposable> disposableGuard = ScopeGuard.Create(disposable);
            AssertNotDisposed(disposable, disposableGuard);
            disposableGuard.Dismiss();
            AssertNotDisposed(disposable, disposableGuard);
            disposableGuard.Dispose();
            AssertNotDisposed(disposable, disposableGuard);
        }

        /// <summary>Tests what happens in the event of a failure.</summary>
        [TestMethod]
        public void FailureTest()
        {
            Disposable disposable = new Disposable();
            ScopeGuard<Disposable> disposableGuard = ScopeGuard.Create(disposable);
            disposableGuard.Dispose();
            Assert.IsTrue(disposable.DisposeCalled);
            AssertThrow<ObjectDisposedException>(delegate { Disposable test = disposableGuard.Resource; });
            disposableGuard.Dispose();
            AssertThrow<ObjectDisposedException>(delegate { Disposable test = disposableGuard.Resource; });
            AssertThrow<ObjectDisposedException>(delegate { disposableGuard.Dismiss(); });
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private static void AssertNotDisposed(Disposable disposable, ScopeGuard<Disposable> disposableGuard)
        {
            Assert.IsFalse(disposable.DisposeCalled);
            Assert.AreSame(disposable, disposableGuard.Resource);
            Assert.IsFalse(disposable.DisposeCalled);
        }

        /// <summary>Mock used for testing <see cref="ScopeGuard"/>.</summary>
        private sealed class Disposable : IDisposable
        {
            private bool disposeCalled;

            /// <summary>See <see cref="IDisposable.Dispose"/>.</summary>
            public void Dispose()
            {
                this.disposeCalled = true;
            }

            internal bool DisposeCalled
            {
                get { return this.disposeCalled; }
            }
        }
    }
}
